home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / AOCE Sample Code / PowerTalk Access Modules / Sample SMSAM / SampleSMSAM Source / ThreadStuff / Failure.cp < prev    next >
Encoding:
Text File  |  1995-07-28  |  5.8 KB  |  225 lines  |  [TEXT/KAHL]

  1. /*
  2.     File:        Failure.cp
  3.  
  4.     Copyright:    © 1991-1994 by Apple Computer, Inc.
  5.                 All rights reserved.
  6.  
  7.     Part of the AOCE Sample SMSAM Package.  Consult the license
  8.     which came with this software for your specific legal rights.
  9.  
  10. */
  11.  
  12.  
  13. #include <Types.h>
  14. #include <Memory.h>
  15. #include <Resources.h>
  16. #include <setjmp.h>
  17.  
  18. #include "Failure.h"
  19.  
  20. #define DEBUGMESSAGES
  21. /*
  22. #define FAILMESSAGES
  23. */
  24.  
  25. #define kResignalingFailure        0x10
  26.  
  27. FailStack*            gFailStack = nil;
  28. NotifyFailureProc    gNotifyProc = nil;
  29.  
  30. /***********************************|****************************************/
  31.  
  32. void * GetExceptionChain ()
  33. {
  34.     return (void*) gFailStack;
  35. }
  36.  
  37. /***********************************|****************************************/
  38.  
  39. void SetExceptionChain ( void * chainTop )
  40. {
  41.     gFailStack = ( FailStack *) chainTop;
  42. }
  43.  
  44. /***********************************|****************************************/
  45.  
  46. /*-------------------------------------------------------------------
  47.     This function is called by the TRY macro
  48. -------------------------------------------------------------------*/
  49. void _SetupTry( FailStack* newFailHandler )
  50. {
  51.     newFailHandler->magicFailID = kMagicFailID;
  52.     /*
  53.     // Clear out the 'error' & 'flags' entries
  54.     */
  55.     newFailHandler->error = noErr;
  56.     newFailHandler->flags = 0;
  57.     /*
  58.     // Push the new entry onto the failure stack
  59.     */
  60.     newFailHandler->next = gFailStack;
  61.     gFailStack = newFailHandler;
  62. }
  63.  
  64. /*-------------------------------------------------------------------
  65.     'PopFailureStack' is called by the ENDTRY macro
  66. -------------------------------------------------------------------*/
  67. void _PopFailureStack()
  68. {
  69.     if( (gFailStack != nil) && (gFailStack->magicFailID == kMagicFailID) )
  70.     {
  71.         /*
  72.         // Pop an entry off the top of the fail stack
  73.         */
  74.         gFailStack = gFailStack->next;
  75.     }
  76.     #ifdef DEBUGMESSAGES
  77.         else
  78.         {
  79.             if( gFailStack == nil )
  80.                 DebugStr( "\pError -- ENDTRY without TRY" );
  81.             else
  82.                 DebugStr( "\pFatal error in PopFailureStack--failure handler stack corrupted" );
  83.         }
  84.     #endif
  85. }
  86.  
  87. /*-------------------------------------------------------------------
  88.     Invoke exception handling if 'theErr' != noErr
  89. -------------------------------------------------------------------*/
  90. void _FailOSErr( OSErr theErr )
  91. {
  92.     if( theErr != noErr )
  93.         _Failure( theErr );
  94. }
  95.  
  96. /*-------------------------------------------------------------------
  97.     Invoke exception handling
  98. -------------------------------------------------------------------*/
  99. void _Failure( OSErr theErr )
  100. {
  101.     #ifdef FAILMESSAGES
  102.         DebugPrintf( "Failure caused by an error %d", theErr );
  103.     #endif
  104.     /*
  105.     // First do a little bit of sanity checking
  106.     */
  107.     if( (gFailStack != nil) && (gFailStack->magicFailID == kMagicFailID) )
  108.     {
  109.         /*
  110.         // If we are already in a failure handler, call
  111.         // 'FailAgain'; don't go back to the same handler!
  112.         */
  113.         if( gFailStack->flags & kInExceptionHandler )
  114.             _FailAgain();
  115.         /*
  116.         // Remember the error that caused the failure &
  117.         // set a bit that indicates that we have invoked
  118.         // exception handling
  119.         */
  120.         gFailStack->error = theErr;
  121.         gFailStack->flags |= kInExceptionHandler;
  122.         /*
  123.         // Record the stack chain in case someone is
  124.         // interested in it later.  Don't blast the
  125.         // old stack chain if we are resignalling, though!
  126.         */
  127.         if( (gNotifyProc != nil) && ((gFailStack->flags & kResignalingFailure) == 0) )
  128.             (*gNotifyProc)();
  129.         
  130.         /*
  131.         // TRY does a setjmp; now we longjmp back to
  132.         // that point with a longjmp.  The 'TRY' macro
  133.         // includes an 'if' statement that is true
  134.         // the first time through and false when we longjmp
  135.         // back to it; the EXCEPTion handler is just the
  136.         // 'else' branch of that 'if' block.
  137.         */
  138.         longjmp( gFailStack->env, 1 );
  139.     }
  140.     #ifdef DEBUGMESSAGES
  141.         else
  142.         {
  143.             if( gFailStack == nil )
  144.                 DebugStr( "\pFatal error in FailOSErr--gFailStack nil" );
  145.             else
  146.                 DebugStr( "\pFatal error in FailOSErr--failure handler stack corrupted" );
  147.         }
  148.     #endif
  149. }
  150.  
  151. /*-------------------------------------------------------------------
  152.     Return the error code that caused the failure.
  153.  
  154.     It is only legal to request TheFailError within an EXCEPT block
  155. -------------------------------------------------------------------*/
  156. OSErr _TheFailError()
  157. {
  158.     if( gFailStack == nil )
  159.         return ePointerNil;
  160.  
  161.     #ifdef DEBUGMESSAGES
  162.         if( gFailStack->magicFailID != kMagicFailID )
  163.             DebugStr( "\pFatal error in TheFailError--failure handler stack corrupted" );
  164.     #endif
  165.         
  166.     return gFailStack->error;
  167. }
  168.  
  169. /*-------------------------------------------------------------------
  170.     It is only legal to call 'FailAgain' from within an EXCEPT
  171.     block.  If called, FailAgain will pass the error that
  172.     caused the exception failure on to the failure handler
  173.     above this one.
  174. -------------------------------------------------------------------*/
  175. void _FailAgain()
  176. {
  177.     OSErr    theErr;
  178.     
  179.     /*
  180.     // Check for programming errors
  181.     */
  182.     if( (gFailStack != nil) && (gFailStack->next != nil) )
  183.     {
  184.         /*
  185.         // Get the error; make sure it is not 'noErr'
  186.         */
  187.         theErr = _TheFailError();
  188.         if( theErr == noErr )
  189.             theErr = eGeneralErr;
  190.         /*
  191.         // Pop off this failure handler and fail again
  192.         */
  193.         _PopFailureStack();
  194.         gFailStack->flags |= kResignalingFailure;
  195.         _Failure( theErr );
  196.     }
  197.     #ifdef DEBUGMESSAGES
  198.         else
  199.         {
  200.             DebugStr( "\pBad call to FailAgain" );
  201.         }
  202.     #endif
  203. }
  204.  
  205. /*-------------------------------------------------------------------
  206.     Install a single routine called at failure time before
  207.     exception processing begins.  This function is used in
  208.     conjunction with ShowStackChain to record and later show
  209.     the stack at the time of failure.
  210. -------------------------------------------------------------------*/
  211. void SetExceptionNotifyProc(NotifyFailureProc notifyProc)
  212. {
  213.     gNotifyProc = notifyProc;
  214. }
  215.  
  216. /*-------------------------------------------------------------------
  217.     This routine is used by ReportError so that it knows whether or
  218.     not it should show the 'sc6' button
  219. -------------------------------------------------------------------*/
  220. Boolean ExceptionNotifyProcInstalled(void)
  221. {
  222.     return gNotifyProc != nil;
  223. }
  224.  
  225.